/*
* ===================================================
*
*       Filename:  game.cc
*
*
*        Created:  12/07/2011 05:21:29 PM
*       Revision:  none
*       Compiler:  gcc
*
*         Author:  durand_y, <durand.yoan@gmail.com>
*
* ===================================================
*/

#include <cstdlib>
#include <cstdio>
#include "error.hh"
#include "game.hh"

Game::Game ()
{
	std::vector <Token> l;
	list_ = l;
}

Game::~Game ()
{

}

Map&
Game::init (std::string file)
{
	int x = 0;
	int y = 0;
	std::stringstream ss;
	std::string s;
	unsigned int i = 0;
	Parser p;

	p.parse_file (file);
	list_ = p.get_token_list ();
	try
	{
		p.find_map ();
		p.find_team ();
	}
	catch (Error& e)
	{
		if (e.get_status () == 1)
			std::cerr << "Error: No map defined in the file: "
			   	<< file <<std::endl;
		if (e.get_status () == 2)
			std::cerr << "Error: No team defined in the file: "
			   	<< file << std::endl;
		if (e.get_status () == 3)
			std::cerr << "Error: No queen defined at least in one team"
			<<	std::endl;
		if (e.get_status () == 5)
			std::cerr << "Error: negative seed." <<std::endl;
		exit (1);
	}
	ss << list_ [i].get_piece ();
	ss >> s;
	ss.ignore ();
	ss >> x;
	ss.clear ();
	my_srand (x);
	i++;
	ss << p.get_token_list ()[i].get_piece ();
	ss >> s;
	ss.ignore ();
	ss >> x;
	ss.ignore ();
	ss >> y;
	ss.clear ();
	Map& m = Map::GetInstance ();
	m.set_width (x);
	m.set_height (y);
	++i;
	for (; i < p.get_token_list ().size (); ++i)
	{
		init_team (m, &i);
		init_resource (m, &i);
		init_obstacle (m, &i);
	}
	return (m);
}

void
Game::init_team (Map& m,
				 unsigned int *i)
{
	std::stringstream ss;
	std::string s;
	int x = 0;
	int y = 0;

	if (list_[*i].get_delim ().compare ("team") == 0)
	{
		std::list <Ant *> list;
		++(*i);
		while (list_[*i].get_delim ().compare ("end") != 0)
		{
			ss << list_[*i].get_piece ();
			ss >> s;
			ss.ignore ();
			ss >> x;
			ss.ignore ();
			ss >> y;
			ss.clear ();

			try
			{
				if ((x < 0) || (y < 0) ||
				   	(x > m.get_width ()) || (y > m.get_height ()))
					Error e (Error::OUT_OF_BOUNDS);
			}
			catch (Error& e)
			{
					if (e.get_status () == 4)
						std::cerr <<
						   	"Error: One or many position are out of bounds"
						   	<< std::endl;
					exit (1);
			}
			if (s.compare("queen") == 0)
			{
				Queen* q = new Queen (x, y, true);
				m.get_map ()[y - 1][x - 1]->set_piece (q);
				q->set_team(m.get_team ().get_ant_list ()->size () + 1) ;
				list.push_back (q);
			}
			if (s.compare ("food_worker") == 0)
			{
				FoodWorker* fw = new FoodWorker (x, y, false);
				m.get_map ()[y - 1][x - 1]->set_piece (fw);
				fw->set_team (m.get_team ().get_ant_list ()->size () + 1);
				list.push_back (fw);
			}
			++(*i);
		}
		m.get_team ().get_ant_list ()->push_back (list);
	}
}

void
Game::init_resource (Map& m,
					 unsigned int *i)
{
	std::stringstream ss;
	std::string s;
	int x = 0;
	int y = 0;

	if (list_[*i].get_delim ().compare ("resource") == 0)
	{
		++(*i);
		while (list_[*i].get_delim ().compare ("end") != 0)
		{
			ss << list_[*i].get_piece ();
			ss >> s;
			ss.ignore ();
			ss >> x;
			ss.ignore ();
			ss >> y;
			ss.clear ();

			if (s.compare ("food") == 0)
			{
				Food* f = new Food (x,y);
				m.get_map ()[y - 1][x - 1]->set_piece (f);
			}
			if (s.compare ("water") == 0)
			{
				Water* w = new Water (x,y);
				m.get_map ()[y - 1][x - 1]->set_piece (w);
			}
			++(*i);
		}
	}
}

void
Game::init_obstacle (Map& m,
					 unsigned int *i)
{
	std::stringstream ss;
	std::string s;
	int x = 0;
	int y = 0;

	if (list_[*i].get_delim ().compare ("obstacle") == 0)
	{
		++(*i);
		while (list_[*i].get_delim ().compare ("end") != 0)
		{
			ss << list_[*i].get_piece ();
			ss >> s;
			ss.ignore ();
			ss >> x;
			ss.ignore ();
			ss >> y;
			ss.clear ();
			Obstacle* o = new Obstacle (x,y);
			m.get_map ()[y - 1][x - 1]->set_piece (o);
			++(*i);
		}
	}
}

void
Game::run (int cycle,
		   Map& m)
{
	std::list<std::list <Ant*> >::iterator it;
	std::list<Ant *>::iterator lit;

	for (int i = 0; i < cycle; i++)
	{
		for (it = m.get_team ().get_ant_list ()->begin ();
			 it != m.get_team ().get_ant_list ()->end (); ++it)
		{
			for (lit = (*it).begin (); lit != (*it).end (); ++lit)
			{
				(*lit)->action ();
			}
		}
	}
}
